package emulator.unittest.history;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import emulator.history.BitStateChange;
import emulator.history.BitStateHistory;

public class BitStateHistoryTest
{
	static final int HISTORY_SIZE = 10; 
	private BitStateHistory history;

	@Before
	public void setUp() throws Exception
	{
		history = new BitStateHistory(HISTORY_SIZE);
	}

	@Test (expected=IllegalArgumentException.class)
	public void testAddDecreasingTicks()
	{
		history.add(new BitStateChange(2, true));
		history.add(new BitStateChange(1, false));
	}

	@Test (expected=IllegalArgumentException.class)
	public void testAddUnchangedState()
	{
		history.add(new BitStateChange(1, true));
		history.add(new BitStateChange(2, true));
	}

	@Test
	public void testGetGreaterOrEqualEmpty()
	{
		assertEquals(-1, history.getGreaterOrEqualIndex(0L));
	}
	
	@Test
	public void testGetLessOrEqualEmpty()
	{
		assertEquals(-1, history.getLessOrEqualIndex(Long.MAX_VALUE));
	}
	
	@Test
	public void testGetGreaterOrEqualSingleEntry()
	{
		history.add(change42);
		assertEquals(0, history.getGreaterOrEqualIndex(41));
		assertEquals(0, history.getGreaterOrEqualIndex(42));
		assertEquals(-1, history.getGreaterOrEqualIndex(43));
	}
	
	@Test
	public void testGetLessOrEqualSingleEntry()
	{
		history.add(change42);
		assertEquals(-1, history.getLessOrEqualIndex(41));
		assertEquals(0, history.getLessOrEqualIndex(42));
		assertEquals(0, history.getLessOrEqualIndex(43));
	}
	
	@Test
	public void testGetGreaterOrEqualSequence()
	{
		initHistory();
		assertEquals(0, history.getGreaterOrEqualIndex(0));
		assertEquals(0, history.getGreaterOrEqualIndex(1));
		assertEquals(1, history.getGreaterOrEqualIndex(7));
		assertEquals(2, history.getGreaterOrEqualIndex(23));
		assertEquals(3, history.getGreaterOrEqualIndex(39));
		assertEquals(4, history.getGreaterOrEqualIndex(99));
		assertEquals(-1, history.getGreaterOrEqualIndex(100));
	}
	
	@Test
	public void testGetLessOrEqualSequence()
	{
		initHistory();
		assertEquals(-1, history.getLessOrEqualIndex(0));
		assertEquals(0, history.getLessOrEqualIndex(1));
		assertEquals(1, history.getLessOrEqualIndex(17));
		assertEquals(2, history.getLessOrEqualIndex(23));
		assertEquals(3, history.getLessOrEqualIndex(43));
		assertEquals(4, history.getLessOrEqualIndex(99));
		assertEquals(4, history.getLessOrEqualIndex(100));
	}

	@Test
	public void testGetRangeEmptyHistory()
	{
		assertEquals(0, history.getRange(0L, Long.MAX_VALUE).length);
	}
	
	@Test
	public void testGetRangeEmpty()
	{
		initHistory();
		assertEquals(0, history.getRange(0, 0).length);
		assertEquals(0, history.getRange(18, 22).length);
		assertEquals(0, history.getRange(100, Long.MAX_VALUE).length);
	}
	
	@Test
	public void testGetRangeFull()
	{
		initHistory();
		BitStateChange [] fullRange = history.getRange(0, Long.MAX_VALUE);
		assertEquals(5, fullRange.length);
		assertEquals(change1, fullRange[0]);
		assertEquals(change17, fullRange[1]);
		assertEquals(change23, fullRange[2]);
		assertEquals(change42, fullRange[3]);
		assertEquals(change99, fullRange[4]);
	}

	@Test
	public void testGetRangePart()
	{
		initHistory();
		BitStateChange [] partRange = history.getRange(2, 50);
		assertEquals(3, partRange.length);
		assertEquals(change17, partRange[0]);
		assertEquals(change23, partRange[1]);
		assertEquals(change42, partRange[2]);
	}

	@Test
	public void testHistorySizeOverflow()
	{
		BitStateChange [] expectedHistory = new BitStateChange [HISTORY_SIZE];
		boolean state = false;
		long tick = 7;
		for (int i = 0; i < HISTORY_SIZE/2; i++)
		{
			history.add(new BitStateChange(tick, state));
			state = !state;
			tick += 3;
		}
		for (int i = 0; i < HISTORY_SIZE; i++)
		{
			expectedHistory[i] = new BitStateChange(tick, state);
			history.add(expectedHistory[i]);
			state = !state;
			tick += 3;
		}
		BitStateChange [] actualHistory = history.getRange(0, Long.MAX_VALUE);
		assertEquals(expectedHistory.length, actualHistory.length);
		for (int i = 0; i < expectedHistory.length; i++)
			assertEquals(expectedHistory[i], actualHistory[i]);
	}
	
	//
	// ------- Test Data --------
	//
	
	private BitStateChange change1 = new BitStateChange(1, true);
	private BitStateChange change17 = new BitStateChange(17, false);
	private BitStateChange change23 = new BitStateChange(23, true);
	private BitStateChange change42 = new BitStateChange(42, false);
	private BitStateChange change99 = new BitStateChange(99, true);
	
	private void initHistory()
	{
		history.add(change1);
		history.add(change17);
		history.add(change23);
		history.add(change42);
		history.add(change99);
	}
}
